//package vn.com.epi.re.data.training;
//
//import java.io.BufferedReader;
//import java.io.BufferedWriter;
//import java.io.File;
//import java.io.FileWriter;
//import java.io.IOException;
//import java.io.InputStreamReader;
//import java.io.OutputStreamWriter;
//import java.util.Calendar;
//import java.util.Collections;
//import java.util.Date;
//import java.util.List;
//import java.util.Map;
//
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import org.apache.hadoop.conf.Configured;
//import org.apache.hadoop.fs.FileSystem;
//import org.apache.hadoop.fs.Path;
//import org.apache.hadoop.hbase.client.Get;
//import org.apache.hadoop.hbase.client.HTableInterface;
//import org.apache.hadoop.hbase.client.Put;
//import org.apache.hadoop.hbase.client.Result;
//import org.apache.hadoop.hbase.client.ResultScanner;
//import org.apache.hadoop.hbase.client.Scan;
//import org.apache.hadoop.hbase.util.Bytes;
//import org.apache.hadoop.util.Tool;
//import org.apache.hadoop.util.ToolRunner;
//import org.apache.mahout.cf.taste.hadoop.similarity.item.ItemSimilarityJob;
//
//import com.google.common.base.Strings;
//import com.google.common.collect.ArrayListMultimap;
//import com.google.common.collect.Lists;
//import com.google.common.collect.Maps;
//import com.google.common.io.Closeables;
//
//import vn.com.epi.re.ApplicationContext;
//import vn.com.epi.re.data.Pair;
//import vn.com.epi.re.data.Pair2;
//import vn.com.epi.re.table.ArticleTable;
//import vn.com.epi.re.table.UserTable;
//import vn.com.epi.re.tools.StringUtils;
//import vn.com.epi.re.tools.SystemUtils;
//import vn.com.epi.re.tools.TableUtils;
//
//public class Backup extends Configured implements Tool {
//
//    private final Log log = LogFactory.getLog(Backup.class);
//    
//    private static final int CONFIG_NUMBER_OF_LOOP_FILTER = 1;
//    
//    public static final long TIME_LIMIT = 172800; // 48 hours
//    public static final int LINE_LIMIT = 150000;
//    public static final int GROUP_SIZE = 1000;
//    
//    private int nUser, nArticle;
//    private String[] userIds;
//    private int[] articleIds;
//    private ArrayListMultimap<Integer, Pair> graph;
//    private Map<String, Integer> uMap;
//    private Map<Integer, Integer> aMap, catMap;    
//    private ItemSimilarityJob itemSimilarityJob;
//    private ArrayListMultimap<String, Integer> userData;
//    private Map<Integer, Integer> articleData;
//    private Map<Integer, Long> firstVisit;
//    
//    /*
//     * 
//     * Chu y sua lai current time 
//     * 
//     */
//    
//    private long current = System.currentTimeMillis() / 1000L;
////    private long current = 1398038400;  
//        
//    public Backup() {        
//        uMap = Maps.newHashMap();
//        aMap = Maps.newHashMap();
//        setConf(ApplicationContext.get().getConf());
//    }
//    
//    private void loadFirstVisit() {
//        HTableInterface table = ApplicationContext.get().getTable(ArticleTable.NAME);
//        firstVisit = Maps.newHashMap();
//        try {
//            Scan scan = new Scan();
//            scan.addColumn(ArticleTable.FAM_MAIN, ArticleTable.COL_FIRST_VISIT_TIMESTAMPS);        
//            ResultScanner rs = table.getScanner(scan);
//            for (Result r:rs) {                
//                int articleId = Bytes.toInt(r.getRow());
//                long timestamp = Bytes.toLong(r.getValue(ArticleTable.FAM_MAIN, ArticleTable.COL_FIRST_VISIT_TIMESTAMPS));
//                firstVisit.put(articleId, timestamp);
//            }
//        } catch (Exception e) {
//            System.out.println("Error while load first visit timestamp: " + e.toString());
//        } finally {
//            TableUtils.closeQuietly(table);
//        }                         
//    }
//    
//    private void loadActionData() {        
//        HTableInterface table = ApplicationContext.get().getTable(UserTable.NAME);
//        userData = ArrayListMultimap.create();
//        articleData = Maps.newHashMap();        
//        try {
//            Scan scan = new Scan();
//            scan.addColumn(UserTable.FAM_MAIN, UserTable.COL_VISITED_ARTICLES);        
//            scan.addColumn(UserTable.FAM_MAIN, UserTable.COL_VISITED_TIMESTAMPS);        
//            ResultScanner rs = table.getScanner(scan);
//            try {
//                for (Result r:rs) {
//                    String userId = Bytes.toString(r.getRow());
//                    String articleCol = Bytes.toString(r.getValue(UserTable.FAM_MAIN, UserTable.COL_VISITED_ARTICLES));
//                    String timestampCol = Bytes.toString(r.getValue(UserTable.FAM_MAIN, UserTable.COL_VISITED_TIMESTAMPS));
//                    String[] articles = articleCol.split(",");
//                    String[] timestamps = timestampCol.split(",");                    
//                    for (int i = 0; i < articles.length; i++) {
//                        int articleId = Integer.parseInt(articles[i]);
//                        long timestamp = Long.parseLong(timestamps[i]);
//                        if (current - timestamp < TIME_LIMIT) {
//                            userData.put(userId, articleId);
//                            if (articleData.containsKey(articleId)) 
//                                articleData.put(articleId, articleData.get(articleId) + 1);
//                            else
//                                articleData.put(articleId, 1);
//                        }
//                    }
//                }
//            } finally {
//                rs.close();
//            }
//        } catch (Exception e) {
//            System.out.println("Error while load data from hbase");
//        } finally {
//            TableUtils.closeQuietly(table);
//        }                
//    }
//    
//    private boolean accept(int articleId) {
//        long sixHours = 21600;
//        long oneDays = 86400;
//        try {
//            long t = current - firstVisit.get(articleId);
//            if (t > TIME_LIMIT)
//                return false;
//            if (t < sixHours) {
//                if (articleData.get(articleId) >= 10)
//                    return true;
//                else
//                    return false;
//            } else if (t < oneDays) {
//                if (articleData.get(articleId) >= 20)
//                    return true;
//                else
//                    return false;
//            } else {
//                if (articleData.get(articleId) >= 30)
//                    return true;
//                else
//                    return false;
//            }                
//        } catch (Exception e) {
//            return false;
//        }
//    }
//    
//    private boolean acceptFilter(int articleId) {
//        long sixHours = 21600;
//        long oneDays = 86400;
//        try {
//            long t = current - firstVisit.get(articleId);
//            if (t > TIME_LIMIT)
//                return false;
//            if (t < sixHours) {
//                if (articleData.get(articleId) >= 10)
//                    return true;
//                else
//                    return false;
//            } else if (t < oneDays) {
//                if (articleData.get(articleId) >= 15)
//                    return true;
//                else
//                    return false;
//            } else {
//                if (articleData.get(articleId) >= 20)
//                    return true;
//                else
//                    return false;
//            }                
//        } catch (Exception e) {
//            return false;
//        }
//    }
//    
//    private boolean acceptArticle(int articleId) {
//        long sixHours = 21600;
//        try {
//            long t = current - firstVisit.get(articleId);
//            if (t > TIME_LIMIT)
//                return false;
//            if (t < sixHours) {
//                if (articleData.get(articleId) >= 10)
//                    return true;
//                else
//                    return false;
//            } else {
//                if (articleData.get(articleId) >= 15)
//                    return true;
//                else
//                    return false;
//            }                 
//        } catch (Exception e) {
//            return false;
//        }
//    }        
//    
//    private void filter() {
//        Map<String, Integer> map = Maps.newHashMap();
//        try {
//            for (int step = 1; step <= CONFIG_NUMBER_OF_LOOP_FILTER; step++) {
//                for (String userId : userData.keySet()) {
//                    int count = 0;
//                    for (int articleId : userData.get(userId)) {
//                        if (accept(articleId))
//                            count++;
//                    }
//                    if (count < 20)
//                        map.put(userId, count);
//                    if (step == CONFIG_NUMBER_OF_LOOP_FILTER && count > 100)
//                        map.put(userId, count);
//                }
//                for (String userId : map.keySet()) {
//                    for (int articleId : userData.get(userId)) {
//                        int read = articleData.get(articleId);
//                        articleData.put(articleId, read - 1);
//                    }
//                    userData.removeAll(userId);
//                }
//                map = Maps.newHashMap();
//            }
//            List<Pair2<String>> list = Lists.newArrayList();
//            for (String userId : userData.keySet()) { 
//                double score = 1000;
//                List<Integer> blackList = Lists.newArrayList();
//                for (int articleId : userData.get(userId)) 
//                    if (!accept(articleId)) {
//                        blackList.add(articleId);
//                    }
//                for (int articleId: blackList)
//                    userData.remove(userId, articleId);
//                for (int articleId : userData.get(userId))
//                    if (articleData.get(articleId) < score)
//                        score = articleData.get(articleId);
//                list.add(new Pair2<String>(userId, score));
//            }
//            Collections.sort(list);
//            for (Pair2<String> p : list) {
//                String userId = p.getFirst();
//                boolean remove = true;
//                for (int articleId : userData.get(userId))
//                    if (!acceptFilter(articleId)) {
//                        remove = false;
//                        break;
//                    }
//                if (remove) {
//                    for (int articleId : userData.get(userId)) {
//                        int read = articleData.get(articleId);
//                        articleData.put(articleId, read - 1);
//                    }
//                    userData.removeAll(userId);
//                }
//            }            
//        } catch (Exception e) {
//            System.out.println("Error while filter data");
//        }
//    }        
//    
//    private String getSubDir() {
//        Date date = new Date(); // your date
//        Calendar cal = Calendar.getInstance();
//        cal.setTime(date);
//        int year = cal.get(Calendar.YEAR);
//        int month = cal.get(Calendar.MONTH) + 1;
//        int day = cal.get(Calendar.DAY_OF_MONTH);
//        int hours = cal.get(Calendar.HOUR_OF_DAY);
//        int minute = cal.get(Calendar.MINUTE);
//        int second = cal.get(Calendar.SECOND);
//        int millis = cal.get(Calendar.MILLISECOND);
//        return year + "-" + month + "-" + day + "-" + hours + "-" + minute + "-" + second + "-" + millis;
//    }
//    
//    private void initial() throws IOException {
//        articleIds = new int[nArticle + 1];
//        userIds = new String[nUser + 1];
//        for (int article : aMap.keySet())
//            articleIds[aMap.get(article)] = article;
//        for (String user : uMap.keySet())
//            userIds[uMap.get(user)] = user;
//    }
//    
//    private int encodeUser(String userId) {
//        int userEnCode;
//        if (uMap.containsKey(userId))
//            userEnCode = uMap.get(userId);
//        else {
//            nUser++;
//            userEnCode = nUser;
//            uMap.put(userId, userEnCode);
//        }        
//        return userEnCode;
//    }
//    
//    private int encodeArticle(int articleId) {
//        int articleEnCode;
//        if (aMap.containsKey(articleId))
//            articleEnCode = aMap.get(articleId);
//        else {
//            nArticle++;
//            articleEnCode = nArticle;
//            aMap.put(articleId, articleEnCode);
//        }
//        return articleEnCode;
//    }
//    
//    private void getFileDataModel(String folder) throws IOException {
//        log.info("-----------* create file data model *------------");
//        FileSystem fs = ApplicationContext.get().getFileSystem();        
//        int index, count, numberOfLines;
//        numberOfLines = 0;
//        index = 0;      
//        count = 0;
//        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fs.create(new Path(folder + "/inp" + index),true)));
//        try {
//                for (String userId: userData.keySet()) {
//                    int userEnCode = encodeUser(userId);
//                    for (int articleId: userData.get(userId)) 
//                        if (acceptArticle(articleId)) {
//                            int articleEnCode = encodeArticle(articleId);
//                            bw.write(userEnCode + "," + articleEnCode + "\n");
//                            numberOfLines++;
//                            count++;
//                            if (count == LINE_LIMIT) {
//                                bw.close();
//                                count = 0;
//                                index++;
//                                bw = new BufferedWriter(new OutputStreamWriter(fs.create(new Path(folder + "/inp" + index), true)));
//                            }
//                        }
//                }
//                System.out.println("Number of lines: " + numberOfLines);
//                log.info("completed create file data model !!!");
//                System.out.println("Number of users: " + nUser);                
//                System.out.println("Number of article: " + nArticle);                
//        } catch (Exception e) {
//            log.info("Error while scan user table: " + e.getMessage());
//            System.out.println("Error while create data model: " + e.toString());
//            System.exit(-1);
//        } finally {
//            userData = null;
//            articleData = null;
//            if (bw != null)
//                try {
//                    bw.close();
//                } catch (Exception e) {                     
//                }
//            initial();
//        }
//    }
//    
//    private void loadCategory() {
//        HTableInterface table = ApplicationContext.get().getTable(ArticleTable.NAME);
//        catMap = Maps.newHashMap();
//        try {
//            Scan scan = new Scan();
//            scan.addColumn(ArticleTable.FAM_MAIN, ArticleTable.COL_CATEGORY_ID);        
//            ResultScanner rs = table.getScanner(scan);
//            for (Result r:rs) {                
//                int articleId = Bytes.toInt(r.getRow());
//                int categoryId = Bytes.toInt(r.getValue(ArticleTable.FAM_MAIN, ArticleTable.COL_CATEGORY_ID));
//                catMap.put(articleId, categoryId);
//            }
//        } catch (Exception e) {
//            System.out.println("Error while load category: " + e.toString());
//        } finally {
//            TableUtils.closeQuietly(table);
//        }                 
//    }
//    
//    private boolean sameCategory(int u, int v) {
//        try {
//            if ((!catMap.containsKey(u)) || (!catMap.containsKey(v)))
//                return false;
//            else {
//                if (catMap.get(u) == 0 || catMap.get(v) == 0) {
//                    return false;
//                }
//                if (catMap.get(u) == catMap.get(v))
//                    return true;
//                else
//                    return false;
//            }
//        } catch (Exception e) {
//            return false;
//        }
//    }
//
//    private void createRelatedGraph(String outputDir) {
//        graph = ArrayListMultimap.create();
//        FileSystem fs = ApplicationContext.get().getFileSystem();        
//        BufferedReader br = null;
//        int index = 0;
//        loadCategory();
//        try {
//            while (true) {
//                String fileName;
//                if (index < 10)
//                    fileName = outputDir + "/part-r-0000" + index;
//                else
//                    fileName = outputDir + "/part-r-000" + index;
//                index++;                
//                Path filePath = new Path(fileName);
//                if (fs.exists(filePath)) {
//                    br = new BufferedReader(new InputStreamReader(fs.open(filePath)));
//                    String line;
//                    while ((line = br.readLine()) != null) {
//                        String[] chunks = line.split("\t");
//                        int i = Integer.parseInt(chunks[0]);
//                        int j = Integer.parseInt(chunks[1]);
//                        int u = articleIds[i];
//                        int v = articleIds[j];
//                        double score = Double.parseDouble(chunks[2]);
//                        if (sameCategory(u, v)) {
//                            graph.put(u, new Pair(v, score));
//                            graph.put(v, new Pair(u, score));
//                        }
//                    }
//                    br.close();
//                } else
//                    break;                
//            }
//        } catch (Exception e) {
//            System.out.println("Error while create related graph: " + e.toString());
//        } finally {
//            if (br != null)
//                try {
//                    br.close();
//                } catch (Exception e) {                    
//                }
//        }
//    }
//    
//    private void importRecommendationsToArticleTable() {
//        HTableInterface articleTable = ApplicationContext.get().getTable(ArticleTable.NAME);
//        List<Get> gets = Lists.newArrayList();
//        List<Put> puts = Lists.newArrayList();
//        log.info("start import new data to article table");
//        try {
//            int numberOfArticles = graph.keySet().size(); 
//            for (int articleId: graph.keySet()) {
//                numberOfArticles--;                
//                byte[] row = Bytes.toBytes(articleId);
//                Get get = new Get(row);
//                gets.add(get);
//                if ((gets.size() == GROUP_SIZE) || (numberOfArticles == 0)) {
//                    Result[] results = articleTable.get(gets);
//                    for (int i = 0; i < results.length; i++) 
//                        if (results[i].getRow() != null)
//                        {
//                            int article = Bytes.toInt(results[i].getRow());
//                            List<Pair> set = graph.get(article);
//                            String re = Bytes.toString(results[i].getValue(ArticleTable.FAM_MAIN, ArticleTable.COL_RECOMMENDATIONS));
//                            String ne = StringUtils.getSubSet(set, 5);
//                            String neighbors = StringUtils.mergeRecommendations(re, ne, 5);
//                            if (!Strings.isNullOrEmpty(neighbors.trim())) {
//                                byte[] value = Bytes.toBytes(neighbors);
//                                Put put = new Put(results[i].getRow());
//                                put.add(ArticleTable.FAM_MAIN, ArticleTable.COL_RECOMMENDATIONS, value);
//                                puts.add(put);
//                            }
//                         }
//                    gets = Lists.newArrayList();
//                    if (puts.size() > 0) {
//                        articleTable.put(puts);
//                        puts = Lists.newArrayList();
//                    }
//                }
//            }
//            log.info("completed import recommendations to article table");
//        } catch (Exception e) {
//            log.info("Error while import recommendations to article table");            
//            System.out.println("Error while import recommendations to article table: " + e.toString());
//        } finally {
//            TableUtils.closeQuietly(articleTable);
//        }        
//    }
//    
//    public void update() throws Exception {
//        String subDir = getSubDir();
//        String inputDir = "input/update/" + subDir;
//        String outputDir = "output/update/" + subDir;
//        String tempDir = "temp/update/" + subDir;
//        try {
//            SystemUtils.deleteHdfsDir(inputDir);
//            loadActionData();
//            loadFirstVisit();
//            filter();
//            getFileDataModel(inputDir);
//            SystemUtils.deleteHdfsDir(outputDir);
//            SystemUtils.deleteHdfsDir(tempDir);
//            log.info("start run item-based recommender");
//            itemSimilarityJob = new ItemSimilarityJob();
//            itemSimilarityJob.setConf(getConf());
//            itemSimilarityJob.run(new String[] { 
//                    "--input", inputDir,
//                    "--output", outputDir,
//                    "--tempDir", tempDir,
//                    "--booleanData", "true",
//                    "--similarityClassname", "SIMILARITY_LOGLIKELIHOOD",
//                    "--maxSimilaritiesPerItem", "100",
//                    "--maxCooccurrencesPerItem", "500"
//                    });
//            log.info("compeleted run item-based recommender");
//            createRelatedGraph(outputDir);
//            importRecommendationsToArticleTable();
//        }  catch (Exception e) {
//            System.out.println("Error while train (update module) data: " + e.toString());
//        } finally {
//            uMap = null;
//            aMap = null;
//            SystemUtils.deleteHdfsDir(inputDir);
//            SystemUtils.deleteHdfsDir(outputDir);
//            SystemUtils.deleteHdfsDir(tempDir);
//        }
//    }
//    
//    private void writeCurrentTime(String path) {
//        BufferedWriter writer = null;
//        try {
//            File file = new File(path);
//            writer = new BufferedWriter(new FileWriter(file));
//            long now = System.currentTimeMillis() / 1000L;
//            writer.write(now + "\n");
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (writer != null)
//                    writer.close();
//            } catch (Exception ex) {
//            }
//        }
//    }
//    
//    @Override
//    public int run(String[] args) throws Exception {
//        if (args.length > 0)
//            writeCurrentTime(args[0]);
//        update();
//        return 0;
//    }
//
//    public static void main(String[] args) throws Exception {
//        long startTime = System.currentTimeMillis();
//        ApplicationContext c = ApplicationContext.init();
//        try {
//            ToolRunner.run(new Backup(), args);
//        } finally {
//            Closeables.closeQuietly(c);            
//        }        
//        long endTime = System.currentTimeMillis();
//        System.out.println("total time used for training: " + (endTime - startTime) + " ms.");
//    }
//}
